/**
 *
 */
package com.abel.bigwater.tlv.server

import com.abel.bigwater.tlv.model.TlvDevPacket
import com.abel.bigwater.tlv.model.TlvException
import com.abel.bigwater.tlv.model.TlvHelper
import com.abel.bigwater.tlv.model.TlvNotEnoughByteException
import org.slf4j.Logger

import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelHandlerContext
import io.netty.handler.codec.ByteToMessageDecoder
import org.slf4j.LoggerFactory

/**
 * @author Abel
 */
class TlvPacketDecoder : ByteToMessageDecoder() {
    private var log = LoggerFactory.getLogger(TlvPacketDecoder::class.java)

    /**
     * Decode the from one [ByteBuf] to an other. This method will be called till either the input
     * [ByteBuf] has nothing to read when return from this method or till nothing was read from the input
     * [ByteBuf].
     *
     * @param ctx           the [ChannelHandlerContext] which this [ByteToMessageDecoder] belongs to
     * @param `buf`            the [ByteBuf] from which to read data
     * @param out           the [List] to which decoded messages should be added
     * @throws Exception    is thrown if an error occurs
     */
    override fun decode(ctx: ChannelHandlerContext?, buf: ByteBuf?, out: MutableList<Any>?) {
        buf?.apply {
            val ba = ByteArray(buf.readableBytes())
            buf.duplicate().readBytes(ba)
            log.info("GOT bytes(${ba.size}): ${TlvHelper.toHexString(ba).toUpperCase()}")
        }

        while (buf?.readableBytes() ?: 0 > 0) {
            val p1 = TlvDevPacket()

            try {
                p1.parse(buf!!)

                out?.add(p1)
            } catch (ex: TlvNotEnoughByteException) {
                log.warn("NOT enought bytes: ${ex.message}")
                break
            } catch (ex: TlvException) {
                log.error("FAIL to parse caused by ${ex.message}", ex)
                ctx?.close()
                break
            }
        }
    }
}
